/*******************************************************************************
* Copyright (c) 2008, Jeferson Jose de Miranda                                 *
* UDESC - Universidade do Estado de Santa Catarina                             *
* All rights reserved.                                                         *
*                                                                              *
* Redistribution and use in source and binary forms, with or without           *
* modification, are permitted provided that the following conditions are met:  *
*     * Redistributions of source code must retain the above copyright         *
*       notice, this list of conditions and the following disclaimer.          *
*     * Redistributions in binary form must reproduce the above copyright      *
*       notice, this list of conditions and the following disclaimer in the    *
*       documentation and/or other materials provided with the distribution.   *
*     * Neither the name of the Universidade do Estado de Santa Catarina nor   *
*       the names of its contributors may be used to endorse or promote        *
*       products derived from this software without specific prior written     *
*       permission.                                                            *
*                                                                              *
* THIS SOFTWARE IS PROVIDED BY JEFERSON JOSE DE MIRANDA "AS IS" AND ANY        *
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED    *
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE       *
* DISCLAIMED. IN NO EVENT SHALL JEFERSON JOSE DE MIRANDA BE LIABLE FOR ANY     *
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES   *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND  *
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF     *
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.            *
*******************************************************************************/

/**
 * \file Camera.hpp
 *
 * \brief Connects to the camera and grab frames from it.
 *
 * \author Jeferson Jose de Miranda
 *
 * This class contains basic functionality concerning the conectivity with the
 * camera. It is based on OpenCV's highgui.h. This file can connect to a webcam
 * and grab frames from it.
 */

#ifndef CAMERA_HPP
#define CAMERA_HPP

// highgui.h is the OpenCV file that has the functions used in this class.
#include <highgui.h>
// Exceptions.hpp groups Move-In exception messages.
#include "Exceptions.hpp"

namespace MoveIn {

    /**
    * \class Camera
    *
    * \brief Connects to the camera and grab frames from it.
    */
    class Camera
    {
        protected:
        /**
        * \var CvCapture *capture
        *
        * \brief The OpenCV video capture structure.
        */
        CvCapture *capture;

        public:
        /**
        * \fn Camera::Camera(int)
        *
        * \brief The camera constructor.
        *
        * Connects to the camera at specified index.
        *
        * \param index
        * The index is used to tell each camera to connect, in the case more
        * than one is avaliable. The default value (-1) tells OpenCV that it
        * can connect to any camera that is not being used.
        */
        Camera(int index = -1);

        /**
        * \fn Camera::~Camera()
        *
        * \brief The camera destructor.
        *
        * Releases the capture.
        */
        ~Camera();

        /**
        * \fn Camera::initialize()
        *
        * \brief Initializes the capture pointer, by grabbing the first frame.
        *
        * The constructor of this class will conect to the camera. But, until
        * the capture is initialized, the methods getWidth() and getHeight() will
        * just return 0. Keep this in mind when calling this methods right
        * after calling the camera constructor.
        */
        void initialize();

        /**
        * \fn Camera::grabFrame()
        *
        * \brief Get a new image from webcam.
        *
        * This is a blocking function. The time it takes to grab a new frame is
        * dependent on the camera's performance. In a real world application,
        * the right thing to do is to put this on a thread, so the application
        * can process other things while the camera is preparing a new frame.
        */
        IplImage* grabFrame();

        /**
        * \fn Camera::getWidth()
        *
        * \brief Get the frame width set on the camera.
        *
        * Returns 0 if the camera capture is not yet initilized (grabbed at
        * least one frame).
        *
        * \return Frame width.
        */
        int getWidth();

        /**
        * \fn Camera::getHeight()
        *
        * \brief Get the frame height set on the camera.
        *
        * Returns 0 if the camera capture is not yet initilized (grabbed at
        * least one frame).
        *
        * \return Frame height.
        */
        int getHeight();
    };

/*******************************************************************************
* MoveIn::Camera::Camera                                                       *
*******************************************************************************/

    Camera::Camera(int index)
    {
        capture = NULL;
        capture = cvCaptureFromCAM(index);
        if(capture == NULL)
        {
            throw new CameraNotFound();
        }
    }

/*******************************************************************************
* MoveIn::Camera::~Camera                                                      *
*******************************************************************************/

    Camera::~Camera()
    {
        cvReleaseCapture(&capture);
    }

/*******************************************************************************
* MoveIn::Camera::initialize                                                   *
*******************************************************************************/

    void Camera::initialize()
    {
        cvQueryFrame(capture);
    }

/*******************************************************************************
* MoveIn::Camera::grabFrame                                                    *
*******************************************************************************/

    IplImage* Camera::grabFrame()
    {
        return cvQueryFrame(capture);
    }

/*******************************************************************************
* MoveIn::Camera::getWidth                                                     *
*******************************************************************************/

    int Camera::getWidth()
    {
        return (int) cvGetCaptureProperty(capture,
                                          CV_CAP_PROP_FRAME_WIDTH);
    }

/*******************************************************************************
* MoveIn::Camera::getHeight                                                    *
*******************************************************************************/

    int Camera::getHeight()
    {
        return (int) cvGetCaptureProperty(capture,
                                          CV_CAP_PROP_FRAME_HEIGHT);
    }
}

#endif
